#include <cstring>
#include <stdexcept>
#include <chrono>
#include <thread>
#include <random>
#include <iostream>

#include "data_codec.h"

// 构造函数：初始化状态、缓冲区和启动超时检查线程
DataCodec::DataCodec(LogLevel log_level)
    : state(State::WAIT_FOR_HEADER)
    , buffer(1024)
    , buffer_pos(0)
    , timeout_ms(1000)
    , running(true)
    , log_level(log_level)
{
    last_state_change = std::chrono::steady_clock::now();
    timeout_thread = std::thread(&DataCodec::timeout_checker, this);
}

// 析构函数：停止超时检查线程并清理资源
DataCodec::~DataCodec()
{
    running = false;
    cv.notify_all();
    if (timeout_thread.joinable())
    {
        timeout_thread.join();
    }
}

// 编码函数：将数据包和数据编码为字节流
std::vector<uint8_t> DataCodec::encode(const pkt_t &packet, const uint8_t *data)
{
    std::vector<uint8_t> encoded_data(packet.len);

    // 填充数据包
    std::memcpy(encoded_data.data(), &packet, sizeof(pkt_t));
    std::memcpy(encoded_data.data() + sizeof(pkt_t), data, packet.data_len);

    // 计算并填充 CRC
    uint16_t crc = calculate_crc(encoded_data.data(), packet.len);
    std::memcpy(encoded_data.data() + offsetof(pkt_t, crc), &crc, sizeof(crc));

    return encoded_data;
}

// 解码函数：将字节流解码为数据包
std::vector<std::unique_ptr<pkt_t>> DataCodec::decode(const std::vector<uint8_t> &data_stream)
{
    std::vector<std::unique_ptr<pkt_t>> decoded_packets;

    for (const auto &byte : data_stream)
    {
        std::lock_guard<std::mutex> lock(mtx); // 锁定互斥量
        process_byte(byte, decoded_packets);    // 处理字节
        cv.notify_all();                       // 通知超时检查线程有新的数据到来
    }

    return decoded_packets;
}

// 设置日志级别
void DataCodec::set_log_level(LogLevel log_level)
{
    this->log_level = log_level;
}

// 超时检查线程函数：定期检查是否超时
void DataCodec::timeout_checker()
{
    while (running)
    {
        std::unique_lock<std::mutex> lock(mtx);
        if (cv.wait_for(lock, std::chrono::milliseconds(100), [this]() { return !running; }))
        {
            break;
        }
        check_timeout(); // 检查超时
    }
}

// 重置状态机
void DataCodec::reset_state_machine()
{
    state = State::WAIT_FOR_HEADER;
    buffer_pos = 0;
    buffer.clear();
    buffer.resize(1024);
    last_state_change = std::chrono::steady_clock::now();
}

// 检查是否超时
void DataCodec::check_timeout()
{
    auto now = std::chrono::steady_clock::now();
    auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(now - last_state_change).count();
    if (duration > timeout_ms)
    {
        log(LogLevel::DEBUG, "超时，重置状态机");
        reset_state_machine();
    }
}

// 更新状态并记录时间戳
void DataCodec::update_state(State new_state)
{
    state = new_state;
    last_state_change = std::chrono::steady_clock::now();
}

// 处理字节：根据当前状态处理输入字节
void DataCodec::process_byte(uint8_t byte, std::vector<std::unique_ptr<pkt_t>> &packets)
{
    switch (state)
    {
        case State::WAIT_FOR_HEADER:
            if (buffer_pos == 0 && byte == 0xAA)
            {
                buffer[buffer_pos++] = byte;
                last_state_change = std::chrono::steady_clock::now(); // 重置时间戳
            }
            else if (buffer_pos == 1 && byte == 0x55)
            {
                buffer[buffer_pos++] = byte;
                update_state(State::READ_LENGTH);
            }
            else
            {
                buffer_pos = 0;
            }
            break;

        case State::READ_LENGTH:
            buffer[buffer_pos++] = byte;
            if (buffer_pos == 4)
            {
                uint16_t len;
                std::memcpy(&len, buffer.data() + 2, sizeof(len));
                buffer.resize(len);
                update_state(State::READ_PAYLOAD);
            }
            break;

        case State::READ_PAYLOAD:
            buffer[buffer_pos++] = byte;
            if (buffer_pos == buffer.size())
            {
                // 校验和验证
                uint16_t crc = calculate_crc(buffer.data(), buffer.size());
                uint16_t packet_crc;
                std::memcpy(&packet_crc, buffer.data() + offsetof(pkt_t, crc), sizeof(pkt_t::crc));
                if (crc == packet_crc)
                {
                    auto pkt = std::unique_ptr<pkt_t>(reinterpret_cast<pkt_t *>(new uint8_t[buffer.size()]));
                    std::memcpy(pkt.get(), buffer.data(), buffer.size());
                    packets.push_back(std::move(pkt));
                }
                else
                {
                    log(LogLevel::ERROR, "CRC校验失败");
                }
                buffer_pos = 0;
                update_state(State::WAIT_FOR_HEADER);
            }
            break;

        default:
            throw std::runtime_error("未知的状态");
    }
}

// 计算校验和
uint16_t DataCodec::calculate_crc(const uint8_t *data, size_t length)
{
    uint16_t crc = 0;
    for (size_t i = 0; i < length; ++i)
    {
        if (i != offsetof(pkt_t, crc) && i != offsetof(pkt_t, crc) + 1)
        {
            crc += data[i];
        }
    }
    return crc;
}

// 日志函数：根据日志级别打印日志信息
void DataCodec::log(LogLevel level, const std::string &message)
{
    if (level <= log_level)
    {
        std::cerr << message << std::endl;
    }
}
